package com.linchong.concurrency.lock;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * @author linchong
 * @version 1.0
 * @Date: 2020-12-09 10:33
 * @Description: LockExample6$
 * 1.线程从AQS线程队列中移除，即释放锁，夹着进入condition的等待队列中，等待改线程需要一个信号
 * 2.线程1释放锁，所以它被唤醒，开始判断是否可以得到锁，故线程获得锁，加入到AQS等待队列中
 * 3.调用发送信号，condition中有线程1的节点，取出，加入到AQS的等待队列中，此时线程1未被唤醒，只是放到队列中，线程2执行
 * 完毕，调用unlock释放锁，AQS中只剩线程1，AQS按照从头到尾，唤醒线程，线程1被唤醒
 * 4.线程1继续开始执行
 *
 * 总结：依靠节点在AQS等待队列和Condition的等待队列中来回移动实现的，condition作为一个条件类，很好的维护了等待信号的
 * 队列，并在适时的时候将节点加入到AQS等待队列中，实现唤醒操作
 * condition也是多线程间协调工具类
 */
@Slf4j
public class LockExample6 {
	public static void main(String[] args) {
		ReentrantLock reentrantLock = new ReentrantLock();
		Condition condition = reentrantLock.newCondition();
		new Thread(()->{
			try {
				reentrantLock.lock();
				//1.等待信号
				log.info("wait singal");
				condition.await();
			}catch (InterruptedException e){
				log.error("exception-1",e);
			}
			//4.得到信号
			log.info("get Signal");
			reentrantLock.unlock();
		}).start();

		new Thread(()->{
			reentrantLock.lock();
			//2.获取锁
			log.info("get lock");
			try {
				Thread.sleep(3_000);
			}catch (InterruptedException e){
				log.error("exception-2",e);
			}
			//3.发送信号
			condition.signalAll();
			log.info("send singal" );
			reentrantLock.unlock();
		}).start();

	}
}
